﻿/*
* DataBind plug-in v1.0.1
* Copyright (c) 2009 James Westgate
* Dual licensed under the MIT and GPL licenses.
*
*/

//Create closure
(function($) {

    //Plugin definition
    $.fn.extend({

        binddata: function(data, map, fn) {

            var $scope = $(this);
            if (fn != null && !$.isFunction(fn)) fn = null;
            if (map != null && $.isFunction(map)) map = null;

            //Return matched set iterator
            return this.each(function() {

                //Array map
                if ($.isArray(data)) {

                    var tagName = this.tagName.toLowerCase();

                    //Map 2d array to a table
                    if (tagName == 'table' || tagName == 'tbody') {
                        bindTable(data);
                    }
                    else if (tagName == 'select') {
                        bindSelect(this, data);
                    }
                }

                //Object map
                else if (typeof (data) == 'object') {

                    bindObject(data);
                }
            });

            function bindObject(json) {

                for (var key in json) {

                    var value = json[key];
                    var selector = '#' + key;

                    //Process child object
                    if (typeof (value) == 'object' && !$.isArray(value)) {
                        bindObject(value);
                        continue;
                    }

                    //Lookup map
                    if (map != null) {
                        var lookup = map[key];
                        if (typeof (lookup) == 'string') selector = lookup;
                    }

                    //Call function if required
                    var result = true;
                    if (fn != null) {

                        var args = { selector: selector, value: value };

                        result = fn(args);

                        if (result) {
                            selector = args.selector;
                            value = args.value;
                        }
                    };

                    //Set value
                    if (result) {

                        //Loop through each item in the selector
                        $(selector, $scope).each(function() {

                            var tag = this.tagName.toLowerCase();
                            var $this = $(this);

                            //Determine if an input use val
                            if (tag == 'input') {
                                $this.val(value);
                            }
                            //Bind arrays to drop down options, single values to a selection
                            else if (tag == 'select') {

                                if ($.isArray(value)) {

                                    bindSelect(this, value);

                                } else {

                                    //Set option value
                                    try {
                                        $this.val(value.toString());
                                    }
                                    catch (e) { };
                                }
                            }
                            //Bind text or html to selector
                            else {

                                // Check to see if the there is html in the text
                                if ($this.text() == $this.html()) {
                                    $this.text(value);
                                }
                                else {
                                    $this.html(value);
                                }
                            }
                        });
                    }
                }
            }

            function bindSelect(element, array) {

                var html = [];
                for (var i in array) {

                    var option = array[i];
                    if (typeof (option) == 'object') {

                        if ($.isArray(option)) {
                            html.push('<option value="');
                            html.push(option[0]);
                            html.push('">');
                            html.push(option[1]);
                        }
                        else {
                            var flag = true;
                            for (var key2 in option) {
                                var value2 = option[key2];

                                if (flag) {
                                    html.push('<option value="');
                                    html.push(value2);
                                    html.push('">');
                                    flag = false;
                                }
                                else {
                                    html.push(value2);
                                    break;
                                }
                            }
                        }
                    }
                    else {
                        html.push('<option>');
                        html.push(option);
                    }

                    html.push('</option>');
                }

                //Replace options with html
                $(element).html(html.join(''));
            }

            function bindTable(array) {

                var is2D = $.isArray(array[0]);
                var html = [];
                var row = [];
                var col;
                var selector = '';
                var result = true;
                var value = null;

                html.push('<tbody>');

                //Loop through each row
                for (var i in array) {
                    row = array[i];
                    selector = '<tr>';
                    result = true;

                    if (fn != null) {

                        var args = { element: selector, row: row, col: i };

                        result = fn(args)

                        if (result) selector = args.element;
                    };

                    //Bind each row
                    if (result) {

                        html.push(selector);

                        //Contain array of values
                        if (is2D) {

                            //Loop through each col
                            for (var i2 in row) {
                                value = row[i2];
                                selector = '<td>';
                                result = true;

                                //Lookup map
                                if (map != null && $.isArray(map)) {
                                    var index = map[i2];
                                    if (typeof (index) == 'number') value = row[index];
                                }

                                //Call any attached function
                                if (fn != null) {

                                    var args = { element: selector, value: value, col: i2 };
                                    result = fn(args);

                                    if (result) {
                                        selector = args.element;
                                        value = args.value;
                                    }
                                };

                                //Bind each col
                                if (result) {
                                    html.push(selector);
                                    html.push(value);
                                    html.push('</td>');
                                }
                            }
                        }

                        //Contains object
                        else if (typeof (row) == 'object') {

                            //Loop through each object key
                            var i = 0;
                            for (var key in row) {
                                value = row[key];
                                selector = '<td>';
                                result = true;

                                //Lookup map
                                if (map != null) {

                                    //Get key by current position in array
                                    key = map[i];
                                    value = row[key];
                                }

                                //Call the attached function
                                if (fn != null) {

                                    var args = { element: selector, key: key, value: value };
                                    result = fn(args);

                                    if (result) {
                                        selector = args.element;
                                        value = args.value;
                                    }
                                };

                                //Bind each col
                                if (result) {
                                    html.push(selector);
                                    html.push(value);
                                    html.push('</td>');
                                }

                                //Break out the loop if end of map
                                if (map != null && i >= map.length - 1) break;

                                i++;
                            }
                        }
                        //Simple type
                        else {
                            value = row;
                            selector = '<td>';
                            result = true;

                            //Ignore map

                            //Call any attached function
                            if (fn != null) {

                                var args = { element: selector, value: value };
                                result = fn(args);

                                if (result) {
                                    selector = args.element;
                                    value = args.value;
                                }
                            };

                            //Bind each col
                            if (result) {
                                html.push(selector);
                                html.push(value);
                                html.push('</td>');
                            }
                        }

                        html.push('</tr>');
                    }
                }

                //Replace the tbody
                html.push('</tbody>');
                $('tbody', $scope).replaceWith(html.join(''));
            }
        },

        unbinddata: function(json, map, fn) {

            var $scope = $(this);
            if (fn != null && !$.isFunction(fn)) fn = null;
            if (map != null && $.isFunction(map)) map = null;

            //Return matched set iterator
            return this.each(function() {

                //Get a list of mapped elements
                var elements = [];

                if (map != null) {

                    for (var key in map) {

                        //Loop through the map selector elements and add each element to the elements collection
                        $(map[key], $scope).each(function() {

                            var tag = this.tagName.toLowerCase();
                            var val = (tag == 'input' || tag == 'select') ? $(this).val() : $(this).text();

                            //Create element
                            elements.push({ element: this, name: key, value: val });
                        });
                    }
                }

                //Get child input and select elements
                $('input, select', element).each(function() {

                    var child = this;
                    var flag = true;

                    //Check elements collection if element already added
                    for (var i2 in elements) {
                        var element = elements[i2];
                        if (element.element == child) {
                            flag = false;
                            break;
                        }
                    }

                    if (flag) {
                        elements.push({ element: this, name: $(child).attr('id'), value: $(child).val() });
                    }
                });

                //Loop through the elements and output as object
                var element;
                var check;

                for (var i in elements) {

                    element = elements[i];
                    if (element.name == '') continue;

                    var values = [];
                    var first = true;

                    //Check for multiple values
                    for (var i2 in elements) {

                        check = elements[i2];
                        if (check.name == '') continue;

                        if (check.name == element.name) {
                            values.push(check.value);

                            if (element != check) check.name = ''; //prevent from being matched again
                        }
                    }

                    //Set the json output variable
                    var result = true;
                    var value = (values.length == 1) ? values[0] : values;

                    //Call function if available
                    if (fn != null) {

                        var args = { selector: element.name, value: value };
                        result = fn(args);

                        if (result) {
                            element.name = selector;
                            value = args.value;
                        }
                    };

                    json[element.name] = value;
                }
            });
        }
    });

    // end of closure
})(jQuery);
